package cn.liccshop.core.service.shopOrderInfo.service;

import cn.liccshop.core.entity.*;
import cn.liccshop.core.proscenium.shopUser.mapper.ShopUserMapper;
import cn.liccshop.core.service.shopCart.mapper.ShopCartMapper;
import cn.liccshop.core.service.shopGoods.mapper.ShopGoodsMapper;
import cn.liccshop.core.service.shopOrderGoods.mapper.ShopOrderGoodsMapper;
import cn.liccshop.core.service.shopOrderInfo.mapper.ShopOrderInfoMapper;
import cn.liccshop.core.service.shopOrderInfo.service.IShopOrderInfoService;
import cn.liccshop.core.service.shopProducts.mapper.ShopProductsMapper;
import cn.liccshop.core.service.shopTransaction.mapper.ShopTransactionMapper;
import cn.liccshop.core.utils.GoodsRedisUtil;
import cn.liccshop.core.utils.ObjectToOtherUtils;
import cn.liccshop.sys.cache.CommonCacheUtil;
import cn.liccshop.sys.constants.Constants;
import cn.liccshop.sys.exception.MySystemException;
import cn.liccshop.sys.utils.DateNumberUtil;
import cn.liccshop.sys.utils.RandomNumberCode;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 订单信息基本表 服务实现类
 * </p>
 *
 * @author LiCC
 * @since 2019-05-13
 */
@Service
public class ShopOrderInfoServiceImpl extends ServiceImpl<ShopOrderInfoMapper, ShopOrderInfo> implements IShopOrderInfoService {

    @Autowired
    private ShopOrderGoodsMapper orderGoodsMapper;
    @Autowired
    private ShopGoodsMapper goodsMapper;
    @Autowired
    private ShopProductsMapper productsMapper;
    @Autowired
    private ShopCartMapper cartMapper;
    @Autowired
    private ShopTransactionMapper transactionMapper;
    @Autowired
    private ShopUserMapper userMapper;
    @Autowired
    private GoodsRedisUtil goodsRedisUtil;
    @Autowired
    private CommonCacheUtil cacheUtil;

    /** 订单从购物车提交 **/
    private final static String ADD_TYPE_CART = "cart";
    /** 订单直接提交 **/
    private final static String ADD_TYPE_GOODS = "goods";


    @Transactional(rollbackFor=Exception.class)
    @Override
    public ShopOrderInfo addInfo(Map<String, Object> map) throws MySystemException {
        /** 判断是直接购买还是从购物车购买 **/
        /** addType: cart-购物车 goods-直接购买**/
        String addType = ObjectToOtherUtils.toString(map.get("addType"));
        ShopOrderInfo shopOrderInfo = null;
        if (StringUtils.isBlank(addType)){
            /** addType 为空，参数异常 **/
            throw new MySystemException("提交方式错误", Constants.INVALID_PARM);
        } else if (ADD_TYPE_CART.equals(addType)){
            /** 订单从购物车提交 **/
            shopOrderInfo = addInfoByShopCart(map);
        } else if (ADD_TYPE_GOODS.equals(addType)){
            /** 订单直接提交 **/
            shopOrderInfo = addInfoByGoods(map);
        } else {
            /** 提交方式参数异常 **/
            throw new MySystemException("提交方式错误", Constants.INVALID_PARM);
        }
        /** 选择不同的处理方法 **/
        return shopOrderInfo;
    }

    @Override
    public boolean orderPay(ShopOrderInfo orderInfo) {
        /** 获取订单信息 **/
        ShopOrderInfo shopOrderInfo = baseMapper.selectById(orderInfo.getId());
        /** 修改订单状态 **/
        baseMapper.updateById(orderInfo);
        /** 如果是支付流程---创建交易记录信息 **/
        if(Constants.ORDER_STATUS_DELIVER.equals(orderInfo.getOrderStatus())){
            /** 获取消费者用户信息 **/
            ShopUser shopUser = userMapper.selectById(shopOrderInfo.getUserId());
            /** 支付流程 新建交易记录 **/
            ShopTransaction transaction = new ShopTransaction()
                    .setTransactionSn(RandomNumberCode.getTransactionSN())
                    .setOrderId(shopOrderInfo.getId())
                    .setOrderSn(shopOrderInfo.getOrderSn())
                    .setUserId(shopUser.getId())
                    .setPhone(shopUser.getPhone())
                    .setAmount(shopOrderInfo.getGoodsAmount())
                    .setType(Constants.TRANSACTIOON_TYPE_SUCC)
                    .setPayTime(orderInfo.getPayTime());
            /** 插入交易数据 **/
            transactionMapper.insert(transaction);
            /** 创建销售记录、销售额和下单量 --- 开始 **/
            /** 下单量添加缓存 **/
            cacheUtil.cacheOrderSalesVolume(1);
            /** 缓存销售额和销售量 **/
            /** 通过订单ID获取订单商品表信息 **/
            List<ShopOrderGoods> orderGoodsList = orderGoodsMapper.selectList(new QueryWrapper<>(new ShopOrderGoods().setOrderId(orderInfo.getId())));
            BigDecimal goodsPrice = new BigDecimal(0.00);
            int goodsVolume = 0;
            for (ShopOrderGoods orderGoods : orderGoodsList){
                /** 暂存总销量 **/
                goodsVolume = goodsVolume + orderGoods.getGoodsNumber();
                /** 暂存总销售额 **/
                goodsPrice = goodsPrice.add(orderGoods.getGoodsPrice().multiply(new BigDecimal(orderGoods.getGoodsNumber())));
            }
            /** 销售量添加缓存 **/
            cacheUtil.cacheGoodsSalesVolume(goodsVolume);
            /** 销售额添加缓存 **/
            cacheUtil.cacheGoodsSalesPrice(goodsPrice);
            /** 创建销售记录、销售额和下单量 --- 结束 **/
        }
        return false;
    }

    @Transactional(rollbackFor=Exception.class)
    @Override
    public boolean returnProcessingSuccOrFail(String orderId, Integer status) {
        if (Constants.GOODS_STATUS_90.intValue() == status){
            /** 退货成功 **/
            /** 修改订单状态 **/
            baseMapper.updateById(new ShopOrderInfo().setId(orderId).setOrderStatus(status));
            /** 修改交易记录状态 **/
            transactionMapper.update(new ShopTransaction().setType(2).setApplayReturnTime(LocalDateTime.now()),new QueryWrapper<>(new ShopTransaction().setOrderId(orderId)));
            /** 修改库存 **/
            List<ShopOrderGoods> orderGoodsList = orderGoodsMapper.selectList(new QueryWrapper<>(new ShopOrderGoods().setOrderId(orderId)));
            int goodsNum = 0;
            BigDecimal price = new BigDecimal(0.00);
            for (ShopOrderGoods orderGoods : orderGoodsList){
                /** 获取商品库存 **/
                Integer num = orderGoods.getGoodsNumber();
                goodsNum += num;
                price = price.add(orderGoods.getGoodsPrice().multiply(new BigDecimal(num)));
                /** 修改商品总库存 **/
                ShopGoods goods = goodsMapper.selectById(orderGoods.getGoodsId());
                goodsMapper.updateById(new ShopGoods().setId(goods.getId()).setGoodsNumber(goods.getGoodsNumber()+num));
                /** 修改商品属性库存 **/
                ShopProducts products = productsMapper.selectById(orderGoods.getProductId());
                productsMapper.updateById(new ShopProducts().setId(products.getId()).setProductNumber(products.getProductNumber()+num));
            }
            /** 修改缓存数据 **/
            ShopOrderInfo orderInfo = baseMapper.selectById(orderId);
            /** 减月总销量 **/
            String data = DateNumberUtil.localDateTimeToYearMonth(orderInfo.getPayTime());
            cacheUtil.cacheGoodsSalesVolume(data, goodsNum);
            cacheUtil.cacheGoodsSalesPrice(data, price);
            cacheUtil.cacheOrderSalesVolume(data, 1);
        } else if (Constants.GOODS_STATUS_95.intValue() == status) {
            /** 退货没通过 失败 **/
            baseMapper.updateById(new ShopOrderInfo().setId(orderId).setOrderStatus(status));
        }
        return true;
    }

    /**
     * 购物车购买
     * @param map
     * @return
     */
    private ShopOrderInfo addInfoByShopCart(Map<String, Object> map) throws MySystemException {
        /** 获取订单商品信息 **/
        List<Map<String, Object>> goodsList = (List<Map<String, Object>>) map.get("goods");
        /** 修改库存信息 增加商品销量信息 **/
        this.updateGoodsInfo(goodsList);
        /** 获取地址信息 **/
        Map<String, Object> addressParams = (Map<String, Object>) map.get("address");
        ShopOrderInfo shopOrderInfo = new ShopOrderInfo();
        /** 装配订单信息 **/
        shopOrderInfo.setUserId(ObjectToOtherUtils.toString(map.get("userId")))
            .setOrderSn(RandomNumberCode.getOrderSN())
            .setOrderStatus(Constants.ORDER_STATUS_PAY)
            .setProvince(ObjectToOtherUtils.toString(addressParams.get("provinceName")))
            .setCity(ObjectToOtherUtils.toString(addressParams.get("cityName")))
            .setDistrict(ObjectToOtherUtils.toString(addressParams.get("districtName")))
            .setStreet(ObjectToOtherUtils.toString(addressParams.get("streetName")))
            .setAddress(ObjectToOtherUtils.toString(addressParams.get("address")))
            .setPhone(ObjectToOtherUtils.toString(addressParams.get("phone")))
            .setConsignee(ObjectToOtherUtils.toString(addressParams.get("consignee")))
            .setPostscript(ObjectToOtherUtils.toString(map.get("postscript")))
            .setGoodsAmount(new BigDecimal(ObjectToOtherUtils.toString(map.get("price"))))
            .setAddTime(LocalDateTime.now());
        /** 保存订单信息 **/
        boolean isSuccess = retBool(baseMapper.insert(shopOrderInfo));
        if (!isSuccess){
            /** 保存订单信息失败 **/
            throw new MySystemException("提交失败", Constants.SYS_ERROR);
        }
        /** 装配订单商品信息 **/
        for(Map<String, Object> goods : goodsList){
            ShopOrderGoods orderGoods = new ShopOrderGoods();
            orderGoods.setOrderId(shopOrderInfo.getId())
                    .setUserId(ObjectToOtherUtils.toString(map.get("userId")))
                    .setGoodsId(ObjectToOtherUtils.toString(goods.get("goodsId")))
                    .setGoodsSn(ObjectToOtherUtils.toString(goods.get("goodsSN")))
                    .setGoodsUrl(ObjectToOtherUtils.toString(goods.get("url")))
                    .setGoodsName(ObjectToOtherUtils.toString(goods.get("goodsName")))
                    .setProductId(ObjectToOtherUtils.toString(goods.get("productsId")))
                    .setGoodsNumber(ObjectToOtherUtils.toInteger(goods.get("cartNum")))
                    .setGoodsPrice(addBigDecimal(goods.get("productPrice"),goods.get("shopPrice")))
                    .setGoodsAttr(ObjectToOtherUtils.toString(goods.get("productName")));
            orderGoodsMapper.insert(orderGoods);
        }
        /** 通过Redis设置订单过期时间 **/
        cacheUtil.cacheOrderPayCountDown(shopOrderInfo.getId());
        return shopOrderInfo;
    }
    /**
     * 直接购买
     * @param map
     * @return
     */
    private ShopOrderInfo addInfoByGoods(Map<String, Object> map){
        return null;
    }

    /**
     * 修改商品库存信息
     * 增加商品销量信息
     * @param goodsList
     */
    private void updateGoodsInfo(List<Map<String, Object>> goodsList) throws MySystemException {
        /** 存储需要购买商品的属性值组合的ID */
        List<String> productsIds = new ArrayList<>();
        /** 存储购物车的ID */
        List<String> cartIds = new ArrayList<>();
        for(Map<String, Object> goods: goodsList){
            /** 保存组合ID **/
            productsIds.add(ObjectToOtherUtils.toString(goods.get("productsId")));
            /** 保存商品ID **/
            cartIds.add(ObjectToOtherUtils.toString(goods.get("id")));
        }
        /** 保存用户销量 也作为后续的热度 **/
        Map<String, Integer> goodsNumber = new HashMap<>();
        synchronized(this){
            /** 查询属性值组合 **/
            List<ShopProducts> productsListDB = productsMapper.selectList(new QueryWrapper<>(new ShopProducts()).in("id", productsIds));
            List<ShopProducts> productsList = new ArrayList<>();
            /** 遍历商品 **/
            for(Map<String, Object> goods: goodsList){
                for (ShopProducts products : productsListDB){
                    /** 组合Id是否相等 **/
                    if (products.getId().equals(ObjectToOtherUtils.toString(goods.get("productsId")))){
                        if (ObjectToOtherUtils.toInteger(goods.get("cartNum"))>products.getProductNumber()){
                            /** 库存不足时抛出异常，自动退出 **/
                            throw new MySystemException("商品编号为“"+ObjectToOtherUtils.toString(goods.get("goodsSN"))+"”的商品已买完，", Constants.GOODS_SOLD_OUT);
                        } else {
                            /** 商品属性组合编辑库存信息，并保存 **/
                            productsList.add(products.setProductNumber(products.getProductNumber() - ObjectToOtherUtils.toInteger(goods.get("cartNum"))));
                            if(goodsNumber.get(products.getGoodsId())==null){
                                /** 不存在商品 **/
                                goodsNumber.put(products.getGoodsId(),ObjectToOtherUtils.toInteger(goods.get("cartNum")));
                            } else {
                                goodsNumber.put(products.getGoodsId(),goodsNumber.get(products.getGoodsId())+ObjectToOtherUtils.toInteger(goods.get("cartNum")));
                            }
                        }
                    }
                }
            }
            for (ShopProducts products : productsList){
                /** 更新商品属性组合库存信息 **/
                productsMapper.updateById(products);
            }
            for (Map.Entry<String, Integer> goods : goodsNumber.entrySet()){
                /** 更新商品库存信息和销量信息 **/
                ShopGoods shopGoods = goodsMapper.selectById(goods.getKey());
                goodsMapper.updateById(shopGoods.setGoodsNumber(shopGoods.getGoodsNumber()-goods.getValue()).setIntegral(shopGoods.getIntegral()+goods.getValue()));
            }
            /** 删除购物车信息 **/
            cartMapper.deleteBatchIds(cartIds);
        }
        /** 锁结束 **/
        /** 开始热度销量保存 **/
        goodsRedisUtil.goodsHot(goodsNumber);
    }

    private BigDecimal addBigDecimal(Object param1, Object param2){
        String decimal1 = ObjectToOtherUtils.toString(param1);
        String decimal2 = ObjectToOtherUtils.toString(param2);
        if (StringUtils.isNotBlank(decimal1)&&StringUtils.isNotBlank(decimal2)){
            return new BigDecimal(decimal1).add(new BigDecimal(decimal2));
        } else if (StringUtils.isNotBlank(decimal1)){
            return new BigDecimal(decimal1);
        } else if (StringUtils.isNotBlank(decimal2)){
            return new BigDecimal(decimal2);
        } else {
            return new BigDecimal("0.00");
        }
    }
}
